package iotwisp.school.user.service;

import iotwisp.base.cqrs.BusinessException;
import iotwisp.base.jwt.JwtConfig;
import iotwisp.base.orm.BaseDao;
import iotwisp.base.util.PwdUtil;
import iotwisp.school.system.entity.Image;
import iotwisp.school.system.entity.SmsValidSaga;
import iotwisp.school.system.exception.SystemException;
import iotwisp.school.system.service.ImageService;
import iotwisp.school.system.service.SmsValidSagaService;
import iotwisp.school.user.command.login_token.CreateLoginTokenDCmd;
import iotwisp.school.user.command.user.CreateUserSCmd;
import iotwisp.school.user.command.user.ModifyUserSCmd;
import iotwisp.school.user.command.user.UserLoginSCmd;
import iotwisp.school.user.command.user.UserRegisterSCmd;
import iotwisp.school.user.entity.LoginToken;
import iotwisp.school.user.entity.User;
import iotwisp.school.user.exception.OrgException;
import iotwisp.school.user.qo.UserQO;
import iotwisp.school.wx.entity.WxUser;
import iotwisp.school.wx.qo.WxUserQO;
import iotwisp.school.wx.service.WxUserService;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;

@Service
@Transactional
public class UserService extends BaseDao<User, UserQO> {

    @Autowired
    private LoginTokenService loginTokenService;
    @Autowired
    private SmsValidSagaService smsValidSagaService;
    @Autowired
    private ImageService imageService;
    @Autowired
    private WxUserService wxUserService;
    @Autowired
    private JwtConfig jwtConfig;

    /**
     * 注册
     *
     * @param cmd
     * @return
     * @throws BusinessException
     */
    public User register(UserRegisterSCmd cmd) throws BusinessException {

        // 获取验证码流程
        SmsValidSaga saga = smsValidSagaService.get(cmd.getSagaId());
        if (saga == null) {
            throw BusinessException.getInstance(BusinessException.NECESSARY_PARAM_NULL, "短信验证码id未传");
        }

        // 判断还能不能验证
        if (saga.canValid()) {

            if (StringUtils.equals(saga.getValidCode(), cmd.getSmsValidCode())) {
                // 创建用户帐号
                CreateUserSCmd createUserSCmd = new CreateUserSCmd();
                BeanUtils.copyProperties(cmd, createUserSCmd);
                return createUser(createUserSCmd);
            } else {
                saga.setFailureTimes(saga.getFailureTimes() + 1);
                throw BusinessException.getInstance(SystemException.VALIDCODE_WRONG, "短信验证码错误");
            }

        } else {
            throw BusinessException.getInstance(SystemException.SMS_INVALID, "短信验证码已失效，请重新发送");
        }

    }

    public LoginToken userLogin(UserLoginSCmd cmd) throws BusinessException {

        // 根据登录名查出用户
        UserQO userQO = new UserQO();
        userQO.setMobile(cmd.getMobile());
        User user = queryUnique(userQO);

        // 不存在抛异常
        if (user == null) {
            throw BusinessException.getInstance(OrgException.USER_NOT_FOUND, "用户不存在");
        }
        // 校验密码是否匹配，不匹配抛异常
        if (!StringUtils.equals(user.getPassword(), PwdUtil.getPwd(cmd.getPassword()))) {
            throw BusinessException.getInstance(OrgException.PASSWORD_WRONG, "用户名或密码错误");
        }

        if (cmd.getHeader() == null) {
            throw BusinessException.getInstance(BusinessException.NECESSARY_PARAM_NULL, "指令头缺少客户端信息");
        }
        // 创建登录令牌
        CreateLoginTokenDCmd createLoginTokenDCmd = new CreateLoginTokenDCmd();
        createLoginTokenDCmd.setClientId(cmd.getHeader().getClientId());
        createLoginTokenDCmd.setClientType(cmd.getHeader().getClientType());

        Calendar expireCalendar = Calendar.getInstance();
        expireCalendar.add(Calendar.MINUTE, jwtConfig.getExpire());
        createLoginTokenDCmd.setExpireDate(expireCalendar.getTime());

        createLoginTokenDCmd.setLoginName(cmd.getMobile());
        createLoginTokenDCmd.setIp(cmd.getHeader().getClientIp());
        createLoginTokenDCmd.setSubjectId(user.getId());
        LoginToken loginToken = loginTokenService.createLoginTokdn(createLoginTokenDCmd);

        return loginToken;
    }

    public User createUser(CreateUserSCmd cmd) throws BusinessException {
        // 检查有没重复注册
        UserQO qo1 = new UserQO();
        qo1.setMobile(cmd.getMobile());
        Integer num = queryCount(qo1);
        if (num > 0) {
            throw BusinessException.getInstance(OrgException.USER_EXIST, "该手机号已经注册过");
        }

        // 检查推荐人
        User regReferrerUser = null;
        UserQO qo2 = new UserQO();
        qo2.setMobile(cmd.getRegReferrerUserMobile());
        regReferrerUser = queryUnique(qo2);
        if (regReferrerUser == null) {
            throw BusinessException.getInstance(OrgException.USER_NOT_FOUND, "注册推荐人不存在");
        }

        Image image = imageService.get(cmd.getHeadImageId());

        // 创建用户
        User user = new User();
        user.create(cmd, image, regReferrerUser);
        save(user);

        //  关联微信用户
        if (StringUtils.isNotBlank(cmd.getWxAccessToken())) {
            WxUserQO wxUserQO = new WxUserQO();
            wxUserQO.setAccessToken(cmd.getWxAccessToken());
            WxUser wxUser = wxUserService.queryUnique(wxUserQO);
            wxUser.setUser(user);
            wxUserService.update(wxUser);
        }

        //	保存事件
//        BizEvent event = createUserRegisterEvent(user);
//        cmd.getEvents().add(event);
        return user;
    }

    public User modifyUser(ModifyUserSCmd cmd) {
        // 查询要修改的用户
        UserQO userQO = new UserQO();
        userQO.setId(cmd.getUserId());
        User user = queryUnique(userQO);

        Image image = null;
        if (StringUtils.isNotBlank(cmd.getHeadImageId())) {
            image = imageService.get(cmd.getHeadImageId());
        }

        user.modify(cmd, image, null);

        update(user);

        return user;
    }

    @Override
    protected Criteria buildCriteria(Criteria criteria, UserQO qo) {
        return criteria;
    }

    @Override
    protected Class<User> getEntityClass() {
        return User.class;
    }

}
